<?php
namespace PsiFramework\Classes\Util\Database\DBMS;

import("Classes.Util.Database.Database");
import("Classes.Util.Database.QueryInterpreter.PostgresSqlQueryInterpreter");
import("Classes.Util.Parameters.DAO.ParametersDAO");
import("Classes.Util.Parameters.DatabaseParameters");

use \PsiFramework\Classes\Util\Database\Database;
use \PsiFramework\Classes\Util\Database\SqlQuery;
use \PsiFramework\Classes\Util\Database\Query\SqlTable;
use \PsiFramework\Classes\Util\Database\Query\SqlType;
use \PsiFramework\Classes\Util\Database\QueryInterpreter\PostgresSqlQueryInterpreter;
use \PsiFramework\Classes\Util\Manager\ParametersManager;
use \PsiFramework\Classes\Util\Parameters\DAO\ParametersDAO;
use \PsiFramework\Classes\Util\Parameters\DatabaseParameters;

/**
 * PsiFramework
 * Php Simple Framework
 *
 * @author Rémi San
 * @version beta
 */

/**
 * The Database is used to connect to a PostgresSQL database
 *
 * @package Util.Database.DBMS
 */
class PostgresSQLDatabase extends Database
{

    public function __construct()
    {
        parent::__construct();
        $parametersManager = ParametersManager::getInstance();
        $databaseParameters = $parametersManager->getDatabaseParameters();
        $connectionString  = "host=".$databaseParameters->getHost()." " ;
        $connectionString .= "port=".$databaseParameters->getPort()." " ;
        $connectionString .= "dbname=".$databaseParameters->getDbName()." " ;
        $connectionString .= "user=".$databaseParameters->getUser()." " ;
        $connectionString .= "password=".$databaseParameters->getPassword();
        $this->_connection = @pg_connect($connectionString);
        if (!$this->_connection) {
            throw new \Exception(
                'Impossible to connect to Database ! Cause : ' . pg_last_error()
            );
        }
    }

    public function __destruct()
    {
        @pg_close($this->_connection);
    }

    public function getSqlType(SqlType $type)
    {
        $interpreter = new PostgresSqlQueryInterpreter(null);
        return $interpreter->getColumnType($type, false, false);
    }

    public function supportsInsteadTriggers()
    {
        return true ;
    }

    function getTableExistsQuery(SqlTable $table, /*bool*/ $view=false)
    {
        return PostgresSqlQueryInterpreter::tableExistsQuery($table, $view);
    }

    function getTableStructureQuery(SqlTable $table)
    {
        return PostgresSqlQueryInterpreter::tableStructureQuery($table);
    }

    /**
     * Execute a query
     *
     * @param       string          $query          the SQL query
     * @return      SQLObject       response
     */
    public function execute(/*string*/ $query)
    {
        $this->_logger->debug($query);
        $result = pg_query($this->_connection, $query);
        if ($result === false) {
            $this->_logger->debug(
                'Query failed! ' . $query . '. ' .
                pg_last_error($this->_connection)
            );
            throw new \Exception(
                'Query failed ! ' . $query . '. ' .
                pg_last_error($this->_connection)
            );
        }
        return $result;
    }

    /**
     * Execute a SqlQuery
     *
     * @param       SqlQuery        $query          the SQL query
     * @return      SQLObject       response
     */
    public function executeQuery(SqlQuery $query)
    {
        $interpreter = new PostgresSqlQueryInterpreter($query);
        return $this->execute($interpreter->toString());
    }

    /**
     * Starts a transaction
     */
    public function startTransaction()
    {
        $this->execute("BEGIN WORK");
    }

    /**
     * Commit transaction
     */
    public function commit()
    {
        $this->execute("COMMIT");
    }

    /**
     * Rollback transaction
     */
    public function rollback()
    {
        $this->execute("ROLLBACK");
    }

    /**
     * Get the next result
     * @see IDatabase::getNextResult()
     */
    public function getNextResult(/*object*/ $result, /*bool*/ $object=true)
    {
        if ($object) {
            return pg_fetch_object($result);
        } else {
            return pg_fetch_array($result);
        }
    }

    /**
     * Returns the current value of the specified sequence
     *
     * @param       string  $sequenceName   the sequence name
     * @return      int             the last id
     */
    public function getLastId(/*string*/ $sequenceName)
    {
        $lastIdQuery = $this->execute("SELECT last_value FROM ".$sequenceName);
        $lastIdResults = pg_fetch_assoc($lastIdQuery);
        $lastId = $lastIdResults["last_value"] ;
        return (int)$lastId;
    }

    /**
     * Returns the value in the good sql format
     *
     * @param       mixed   $value          the value
     * @param       bool    $quotes         display quotes
     * @return      mixed   the formatted value
     */
    public function getValue(/*mixed*/ $value, /*bool*/ $quotes)
    {
        if ($value != null) {
            if ($quotes) {
                $value = "'".pg_escape_string($value)."'" ;
            }
        } else {
            $value = "NULL" ;
        }
        return $value ;
    }

    /**
     * Returns the boolean value from the sql format
     *
     * @param       mixed   $value          the value
     */
    public function getBooleanValue(/*mixed*/ $value)
    {
        if ($value == 'f') {
            return false ;
        } else {
            return true ;
        }
    }
}
